<template>
  <div>
    <el-row :gutter="15">
      <!-- 视频墙 -->
      <el-col :span="18">
        <div class="meeting-container">
          <el-scrollbar height="650px" id="videoListContainer">
            <div class="video-list">
              <!--当前用户排在视频墙第一位-->
              <div class="video">
                <div class="user">
                  <img class="photo" :src="mine.photo"/>
                  <span class="name">{{ mine.name }}{{ shareStatus ? '（共享中）' : '' }}</span>
                </div>
                <!--当前视频信号-->
                <div id="localStream"></div>
              </div>
              <!--其他参会人-->
              <div class="video" v-for="one in memberList">
                <div class="user">
                  <img class="photo" :src="one.photo"/>
                  <span class="name">{{ one.name }}</span>
                </div>
                <!--其他参会人视频信号-->
                <div :id="one.id" class="remote-stream" @dblclick="bigVideoHandle(one.id)"></div>
              </div>
            </div>
          </el-scrollbar>
          <div id="videoBig" @dblclick="smallVideoHandle()"></div>
        </div>
        <p class="desc">
          会议过程中，不需要发言的会场要主动将本地会场的麦克风关闭，保证会场安静，当需要发言时要及时打开麦克风。
          会议过程中，需要发言讨论时，先打开麦克风向主会场提出请求，得到同意后再继续发言，否则请继续保持静音。
          发言时，尽量保持同时只有一个人说话，不要多人同时讲话，避免造成会议声音嘈杂，影响会议进行。
          在会议进行过程中，尽量控制会场噪音，不要在会场中随意走动
        </p>
      </el-col>
      <!-- 用户列表区域 -->
      <el-col :span="6">
        <el-card shadow="never">
          <template #header>
            <div class="card-header"><span>用户列表</span></div>
          </template>
          <el-scrollbar height="555px">
            <ul class="user-list">
              <li v-for="one in userList">
                <img class="mic" src="../../assets/trtc/mic.png"/>
                <div class="mic-container">
                  <img
                      class="mic-green"
                      :id="'mic-' + one.userId"
                      src="../../assets/trtc/mic-green.png"
                  />
                </div>
                <span>{{ one.dept }} - {{ one.name }}</span>
              </li>
            </ul>
          </el-scrollbar>
        </el-card>
        <div class="meeting-operate">
          <button :class="meetingStatus ? 'phone-btn-off' : 'phone-btn-on'" @click="phoneHandle"></button>
          <button :class="videoStatus ? 'video-btn-on' : 'video-btn-off'" @click="videoHandle"></button>
          <button :class="micStatus ? 'mic-btn-on' : 'mic-btn-off'" @click="micHandle"></button>
          <button :class="shareStatus ? 'share-btn-on' : 'share-btn-off'" @click="shareHandle"></button>
        </div>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import TRTC from 'trtc-js-sdk';
import $ from 'jquery';

export default {
  data: function () {
    return {
      meetingId: null,
      uuid: null,
      appId: null,
      userSign: null,
      userId: null,
      roomId: null,
      meetingStatus: false,
      videoStatus: true,
      micStatus: true,
      shareStatus: false,
      userList: [], //进入会场的用户列表
      mine: {},
      memberList: [], //会议成员列表
      client: null,
      localStream: null,
      shareStream: null,
      stream: {}, //所有的远端流
      bigVideoUserId: null //大屏显示远端流的用户ID，切换回小屏幕的时候使用
    };
  },
  created() {
    // 获取页面跳转传递过来的参数
    let params = this.$route.params;
    this.meetingId = params.meetingId;
    this.uuid = params.uuid;

    // 请求参数
    let data = {meetingId: this.meetingId};


    // 查询会议所有参会人，生成视频墙
    this.$http("meeting/searchOnlineMeetingMembers", "POST", data, true, resp => {
      if (resp.code === 200) {
        let list = resp.list;
        if (list != null && list.length > 0) {
          this.mine = list[0];
          for (let i = 1; i < list.length; i++) {
            this.memberList.push(list[i]);
          }
        }
      }
    })

    // 查询视频会议室的ID
    data = {
      uuid: this.uuid
    }
    this.$http("meeting/searchRoomIdByUuid", "POST", data, true, resp => {
      if (resp.roomId === null) {
        this.$message({
          message: "不存在的视频会议",
          type: "error",
          duration: 1200
        })
      } else {
        this.roomId = resp.roomId;
      }
    })

  },
  methods: {
    phoneHandle() {
      let _this = this;
      // 检查当前浏览器是否支持在线视频会议
      TRTC.checkSystemRequirements().then(checkResult => {
        if (!checkResult.result) {
          this.$alert("当前浏览器不支持在线视频会议", '提示信息', {
            confirmButtonText: '确定'
          })
        } else {
          _this.meetingStatus = !_this.meetingStatus;

          // 进入视频会议室
          if (_this.meetingStatus) {
            // 记录麦克风和摄像头的状态
            _this.video = true;
            _this.micStatus = true;
            // TRTC日志输出级别
            TRTC.Logger.setLogLevel(TRTC.Logger.LogLevel.ERROR);

            // 发起请求，生成用户签名（进入视频会议才需要用户签名，不需要提前生成） 异步～！
            _this.$http("meeting/searchMyUserSig", "GET", {}, false, resp => {
              if (resp.code === 200) {
                _this.appId = resp.appId;
                _this.userSig = resp.userSig;
                _this.userId = resp.userId
              }
            })

            // 创建TRTCClient对象
            const client = TRTC.createClient({
              mode: 'rtc',
              sdkAppId: _this.appId,
              userId: _this.userId + "",
              userSig: _this.userSig
            });

            _this.client = client;

            // 监听新增远端流事件（用户进入会议室的时候触发）
            client.on("stream-added", event => {
              let remoteStream = event.stream;
              // 订阅远端流
              client.subscribe(remoteStream);
              // 从远端流获得远程用户userId （创建TrtcClient对象时候的参数）
              let userId = remoteStream.getUserId();

              // 把新上线的用户添加到页面右侧的在线人员列表中
              _this.putUserList(_this, userId);

              // 把远端流保存在模型层JSON中，将来大屏显示的时候要找到某个远端流停止小窗口播放，切换到大窗口播放
              _this.stream[userId] = remoteStream;
            })

            // 远端流订阅成功事件
            client.on('stream-subscribed', event => {
              let remoteStream = event.stream;
              let userId = remoteStream.getUserId();
              // 找到视频墙中某个远程用户的格子，把其中用于显示视频的div，置顶覆盖用户信息
              $('#' + userId).css({'z-index': 1});
              // 把这个置顶的div中播放远端音视频讯号
              remoteStream.play(userId + "");
            })

            // 定远远端删除流事件 （远程用户退出会议室）
            client.on("stream-removed", event => {
              let remoteStream = event.stream;
              // 取消订阅该远程流
              client.unsubscribe(remoteStream);
              let userId = remoteStream.getUserId();

              // 在页面右侧的用户列表中删除该用户
              let i = _this.userList.findIndex(item => {
                return item.userId == userId
              });
              _this.userList.splice(i, 1);

              // 停止播放远端视频，并且关闭远端流
              remoteStream.stop();
              remoteStream.close();

              // 删除模型层JSON中保存的远端流对象
              delete _this.stream[userId];

              // 把视频墙中该用户格子的视频div控件置底，显示用户基本信息
              $('#' + userId).css({'z-index': '-1'});
              $('#' + userId).html("");
            })

            // 订阅语音事件（无论本地还是远端说话，都会触发这个事件）
            client.on("audio-volume", event => {
              /**
               * userId： 那个用户
               * audioVolume： 音量大小
               * stream：流对象
               */
              event.result.forEach(({userId, audioVolume, stream}) => {
                if (audioVolume > 5) {
                  $('#mic-' + userId).css('top', `${100 - audioVolume * 3}%`)
                } else {
                  $('#mic-' + userId).css('top', '100%')
                }
              })
            });

            // 开启音量回调函数，并设置每30ms触发一次事件
            client.enableAudioVolumeEvaluation(30);

            // 进入视频会议
            client
                .join({
                  roomId: _this.roomId
                })
                .then(() => {
                  // 执行签到
                  _this.$http("meeting/updateMeetingPresent", "POST", {meetingId: _this.meetingId}, true, resp => {
                    if (resp.code === 200 && resp.rows === 1) {
                      this.$message({
                        message: "签到成功",
                        type: "success",
                        duration: 1500
                      })
                    }
                  })
                  // 成功进入会议室，然后创建本地流
                  const localStream = TRTC.createStream({
                    userId: _this.userId + "",
                    audio: true,
                    video: true
                  });
                  // 把本地流保存到模型层
                  _this.localStream = localStream;
                  // 设置分辨率
                  localStream.setVideoProfile("480p");
                  // 把自己添加到上线用户列表中
                  _this.putUserList(_this, _this.userId);
                  // 初始化本地音视频流
                  localStream
                      .initialize()
                      .then(() => {
                        console.log("初始化本地音视频流成功");
                        // 视频墙中第一个格子中的视频div置顶
                        $('#localStream').css({'z-index': 1});
                        // 播放本地音视频流, 传入控件（dom）id
                        localStream.play('localStream');
                        // 向远端用户推送本地流
                        client.publish(localStream)
                            .then(() => {
                              console.log("本地流发布成功");
                            })
                            .catch(error => {
                              console.error("本地流发布失败" + error);
                            })
                      })
                      .catch(error => {
                        console.error("初始化本地音视频流失败" + error);
                      })
                })
                // 进入视频会议失败
                .catch(error => {
                  console.error("进入房间失败" + error);
                })

          } else { // 退出视频会议
            // 关闭视频会议
            // 获取当前本地使用的流， 有可能是本地流或者共享流
            let stream = this.getStream();

            // 执行取消发布
            _this.client.unpublish(stream).then(() => {
              // 执行退出
              _this.client
                  .leave()
                  .then(() => {
                    // 退出成功
                    console.log("成功退出会议室")
                    // 关闭本地流或者共享流
                    stream.stop();
                    stream.close();
                    // 清空模型层的本地流
                    _this.localStream = null;
                    _this.shareStream = null;
                    // 清空模型层的远端流
                    _this.stream = {};
                    // 销毁TRTCClient对象
                    _this.client = null;
                    // 清空在线用户列表
                    _this.userList = [];
                    _this.videoStatus = false;
                    _this.micStatus = false;
                    _this.shareStatus = false;
                    // 视频墙上本地流div区域置底
                    $('#localStream').css('z-index', '-1');
                    $('#localStream').html("");
                    // 如果是播放大屏视频的时候退出会议，退出会议后需要隐藏大屏，然后显示视频墙界面
                    if (_this.bigVideoUserId !== null) {
                      $('#videoBig').hide();
                      $('#videoListContainer').show();
                      _this.bigVideoUserId = null;
                    }
                  })
                  .catch(error => {
                    console.error("成功退出会议室失败" + error);
                  })
            })
          }
        }
      })
    },
    // 切换大屏
    bigVideoHandle(userId) {
      // 记录全屏显示的远端用户userId，切回小屏会用到
      this.bigVideoUserId = userId;
      // 隐藏视频墙
      $('#videoListContainer').hide();
      // 显示大屏控件
      $('#videoBig').show();

      // 停止该用户的远程视频在屏幕墙格子的播放
      this.stream[userId].stop();
      // 远端视频在大屏播放
      this.stream[userId].play("videoBig");
    },
    // 关闭大屏显示
    smallVideoHandle() {
      // 停止大屏播放远端视频
      this.stream[this.bigVideoUserId].stop();
      // 在相应的小屏播放远端视频
      this.stream[this.bigVideoUserId].play(this.bigVideoUserId);
      this.bigVideoUserId = null;
      // 隐藏大屏控件
      $('#videoBig').hide();
      // 显示视频墙
      $('#videoListContainer').show();
    },
    // 开启或者关闭摄像头
    videoHandle() {
      if (this.shareStatus) {
        this.$alert("屏幕共享中无法开关摄像头", "提示信息", {
          confirmButtonText: "确定"
        })
        return false;
      }
      if (this.videoStatus) {
        // 关闭摄像头
        this.localStream.muteVideo();
      } else {
        // 开启摄像头
        this.localStream.unmuteVideo();
      }
      this.videoStatus = !this.videoStatus;
    },
    // 开启或者关闭麦克风
    micHandle() {
      let stream = this.getStream();
      if (this.micStatus) {
        // 关闭话筒
        stream.muteAudio();
      } else {
        // 开启话筒
        stream.unmuteAudio();
      }
      this.micStatus = !this.micStatus;
    },
    // 本地屏幕共享，广播推流
    shareHandle() {
      let _this = this;
      // 判断用户是否进入视频会议室
      if (!_this.meetingStatus) {
        _this.$alert('请先进入视频会议才能共享屏幕', '提示信息', {
          confirmButtonText: "确定"
        })
        return false;
      }

      // 检查浏览器是否支持屏幕共享
      if (!TRTC.isScreenShareSupported()) {
        // 提示当前浏览器不支持屏幕共享
        _this.$alert('当前浏览器不支持屏幕共享', '提示信息', {
          confirmButtonText: "确定"
        })
        return false;
      }
      _this.shareStatus = !_this.shareStatus;
      // 开始屏幕共享
      if (_this.shareStatus) {
        // 创建共享流
        let shareStream = TRTC.createStream({
          audio: _this.micStatus,
          screen: true,
          userId: _this.userId
        })
        // 设置分辨率
        shareStream.setScreenProfile('1080p');
        // 缓存共享流
        _this.shareStream = shareStream;
        // 初始化共享流
        shareStream
            .initialize()
            .then(() => {
              // 取消推送本地视频流
              _this.client.unpublish(_this.localStream).then(() => {
                // 关闭本地流
                _this.localStream.close();
                // 销毁本地流
                _this.localStream = null;
                // 隐藏本地视频窗口
                $('#localStream').css({'z-index': -1});
                // 向远端推送共享流
                _this.client.publish(shareStream);
              })
            })
            .catch(err => {
              console.error("初始化共享流失败" + err);
            })
        // 关闭屏幕共享
      } else {
        // 重建本地视频流
        let localStream = TRTC.createStream({
          userId: _this.userId,
          audio: _this.micStatus,
          video: _this.videoStatus
        });
        // 缓存本地流
        _this.localStream = localStream;
        // 设置分辨率
        localStream.setVideoProfile('1080p');
        // 初始化本地流
        localStream
            .initialize()
            .then(() => {
              console.log("初始化本地流成功");
              // 取消屏幕共享流推流
              _this.client.unpublish(_this.shareStream).then(() => {
                // 关闭共享流
                _this.shareStream.close();
                // 销毁共享流
                _this.shareStream = null;
                // 显示本地视频窗口
                $('#localStream').css({'z-index': 1});
                // 播放本地流
                localStream.play('localStream');
                // 向远端推送本地视频流
                _this.client
                    .publish(localStream)
                    .then(() => {
                      console.log("本地流发布成功");
                    })
                    .catch(err => {
                      console.error("本地流发布失败" + err);
                    })
              })
            })
            .catch(err => {
              console.error("初始化本地流失败" + err);
            })
      }
    },
    // 用于判断当前本地使用的是本地流还是共享流，并返回相应的对象
    getStream() {
      let stream = null;
      if (this.localStream != null) {
        stream = this.localStream;
      } else if (this.shareStream != null) {
        stream = this.shareStream;
      }
      return stream
    },
    putUserList(_this, id) {
      _this.$http("user/searchNameAndDept", "POST", {id}, true, resp => {
        if (resp.code === 200) {
          let name = resp.name;
          let dept = resp.deptName;
          _this.userList.push({userId: id, name: name, dept: dept})
        }
      })
    }
  },
}
</script>

<style lang="less" scoped="scoped">
@import url('src/style/meeting_video.less');
</style>
